package com.hqd.utils.file;

import com.hqd.utils.file.filter.SuffixNameFilter;
import com.iheartradio.m3u8.Encoding;
import com.iheartradio.m3u8.Format;
import com.iheartradio.m3u8.PlaylistParser;
import com.iheartradio.m3u8.data.Playlist;
import com.iheartradio.m3u8.data.TrackData;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileExistsException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.util.List;

/**
 * ffmpeg -allowed_extensions ALL -protocol_whitelist "file,http,crypto,tcp" -i  G:\FFOutput\fileList.txt  -c copy G:\FFOutput\test.mp4 包含key的解析命令
 */
public class M3U8Utils {
    public final static String SUFFIX_NAME_M3U8 = SimpleFileUtils.SUFFIX_NAME_M3U8;
    public final static String SUFFIX_NAME_TS = SimpleFileUtils.SUFFIX_NAME_TS;
    public final static String SUFFIX_NAME_MP4 = SimpleFileUtils.SUFFIX_NAME_MP4;
    public final static String SUFFIX_NAME_TXT = SimpleFileUtils.SUFFIX_NAME_TXT;

    /**
     * @param ffmpegPath
     * @param rootPath
     * @param isAddSuffix
     * @throws IOException
     */
    public static void mergeAllTSFiles(String ffmpegPath, File rootPath, boolean isAddSuffix) throws IOException {
        if (SimpleFileUtils.isFile(rootPath)) {
            return;
        }
        List<File> m3u8Files = SimpleFileUtils.searchFile(rootPath, SUFFIX_NAME_M3U8, false, false, true);
        PlaylistParser parser = null;
        for (File f : m3u8Files) {
            parser = new PlaylistParser(new FileInputStream(f), Format.EXT_M3U, Encoding.UTF_8);
            try {
                Playlist playlist = parser.parse();
                List<TrackData> tracks = playlist.getMediaPlaylist().getTracks();
                String tsName = getTsName(tracks);
                File tsFullPath = new File(rootPath, tsName);
                if (SimpleFileUtils.isFile(tsFullPath)) {
                    throw new FileNotFoundException(tsFullPath.toString());
                }
                String tsFullPathStr = tsFullPath.getAbsolutePath();
                if (isAddSuffix) {
                    SimpleFileUtils.addDirFilesSuffix(tsFullPath, SUFFIX_NAME_TS);
                }
                String listFilePath = writeFileListText(rootPath, tsName, tracks, isAddSuffix);
                String[] cmd = {"cmd", "/C",
                        String.format("start  %s  -f concat -safe 0 -i %s -c copy %s -y", ffmpegPath,
                                "\"" + listFilePath + "\"",
                                "\"" + tsFullPathStr.substring(0, tsFullPathStr.lastIndexOf('.')) + SUFFIX_NAME_MP4 + "\"")
                };
                Runtime.getRuntime().exec(cmd);
            } catch (Exception e) {
                throw new IOException(e);
            }
        }

    }

    /**
     * 获取ts文件路径名
     *
     * @param trackDataList
     * @return
     */
    private static String getTsName(List<TrackData> trackDataList) {
        if (CollectionUtils.isNotEmpty(trackDataList)) {
            String uri = trackDataList.get(0).getUri();
            if (StringUtils.isNotBlank(uri) && uri.startsWith("file://")) {
                int end = uri.lastIndexOf('/');
                if (end != -1) {
                    int start = uri.substring(0, end).lastIndexOf('/');
                    if (start != -1) {
                        return uri.substring(start + 1, end);
                    }
                }
            }
        }
        return null;
    }

    private static String writeFileListText(File savePath, String name, List<TrackData> trackDataList, boolean isContainsSuffix) throws IOException {
        if (StringUtils.isBlank(name)) {
            return null;
        }
        if (CollectionUtils.isNotEmpty(trackDataList)) {
            FileUtils.forceMkdir(savePath);
            File listFileText = new File(savePath, name.substring(0, name.lastIndexOf('.')) + "_list" + SUFFIX_NAME_TXT);
            if (listFileText.exists()) {
                throw new IOException(String.format("文件'%s'已存在", listFileText));
            }
            StringBuilder sb = new StringBuilder();
            File tsPath = new File(savePath, name);
            if (tsPath.exists()) {
                trackDataList.stream().forEach((trackData) -> {
                    String uri = trackData.getUri();
                    if (StringUtils.isNotBlank(uri) && uri.startsWith("file://")) {
                        int index = uri.lastIndexOf('/');
                        if (index != -1) {
                            sb.append("file  ")
                                    .append("'")
                                    .append(tsPath.getAbsolutePath() + File.separator + uri.substring(index + 1));
                            if (isContainsSuffix) {
                                sb.append(SUFFIX_NAME_TS);
                            }
                            sb.append("'").append(System.lineSeparator());
                        }
                    }
                });
                try (BufferedWriter bw = new BufferedWriter(new FileWriter(listFileText))) {
                    bw.write(sb.toString());
                } catch (IOException e) {
                    throw e;
                }
                return listFileText.getAbsolutePath();
            }
        }
        return null;
    }

    /**
     * 合并ts文件
     *
     * @param ffmpegPath ffmpeg路径
     * @param listFile   列表文件路径
     * @param savePath   保存路径
     * @param videoName  生成视频名称
     * @throws IOException
     */
    public static void mergeTSFiles(String ffmpegPath, File listFile, File savePath, String videoName) throws IOException {
        if (SimpleFileUtils.isDir(listFile)) {
            return;
        }
        if (savePath.isFile()) {
            return;
        }
        if (!savePath.exists()) {
            savePath.mkdirs();
        }
        File mp4 = new File(savePath, videoName + SUFFIX_NAME_MP4);
        if (mp4.exists()) {
            throw new FileExistsException(String.format("文件'%s'已存在", mp4));
        }
        String[] cmd = {"cmd", "/C",
                String.format("start %s -f concat -safe 0 -i %s -c copy %s -y",
                        ffmpegPath, listFile.getAbsolutePath(),
                        mp4.getAbsolutePath())
        };
        Runtime.getRuntime().exec(cmd);
    }


    /**
     * 生成ts合并列表
     *
     * @param file   目标文件夹
     * @param suffix 后缀名
     * @throws IOException
     */
    public static String writeFileListText(File file, String savePath, String suffix) throws IOException {
        if (StringUtils.isBlank(suffix) || SimpleFileUtils.isFile(file)) {
            return null;
        }
        File path = new File(savePath);
        if (!path.exists()) {
            path.mkdirs();
        }
        File fileList = new File(path, file.getName() + "_list" + SUFFIX_NAME_TXT);
        if (fileList.exists()) {
            throw new FileExistsException(String.format("文件'%s'已存在", fileList));
        }
        File[] files = file.listFiles(new SuffixNameFilter(suffix));
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(fileList))) {
            for (File f : files) {
                bw.write("file  '" + f.getPath() + "'");
                bw.newLine();
            }
        }
        return fileList.getPath();
    }
}
